#include "tcp_socket.h"

namespace Common {
  /// Create TCPSocket with provided attributes to either listen-on / connect-to.
  auto TCPSocket::connect(const std::string &ip, const std::string &iface, int port, bool is_listening) -> int {
    // 对于 FIFOSequencer 等组件，需要抓取内核时间戳，因此 needs_so_timestamp=true。
    const SocketCfg socket_cfg{ip, iface, port, false, is_listening, true};
    socket_fd_ = createSocket(logger_, socket_cfg);  // createSocket 会通过 Logger 记录调用细节。

    // 存储远端地址（监听场景下为本地 INADDR_ANY/port），后续 recvmsg/send 需要用到。
    socket_attrib_.sin_addr.s_addr = INADDR_ANY;
    socket_attrib_.sin_port = htons(port);
    socket_attrib_.sin_family = AF_INET;

    return socket_fd_;
  }

  /// Called to publish outgoing data from the buffers as well as check for and callback if data is available in the read buffers.
  auto TCPSocket::sendAndRecv() noexcept -> bool {
    // ctrl 缓冲区用于接收 SCM_TIMESTAMP 控制信息。
    char ctrl[CMSG_SPACE(sizeof(struct timeval))];
    auto cmsg = reinterpret_cast<struct cmsghdr *>(&ctrl);

    // iovec 指向 inbound buffer 中尚未填充的空间，recvmsg 直接写入。
    iovec iov{inbound_data_.data() + next_rcv_valid_index_, TCPBufferSize - next_rcv_valid_index_};
    msghdr msg{&socket_attrib_, sizeof(socket_attrib_), &iov, 1, ctrl, sizeof(ctrl), 0};

    // 非阻塞读取，可同时获取控制信息（内核时间戳等）。
    const auto read_size = recvmsg(socket_fd_, &msg, MSG_DONTWAIT);
    if (read_size > 0) {
      next_rcv_valid_index_ += read_size;  // 更新有效数据长度，供上层解析。

      Nanos kernel_time = 0;
      timeval time_kernel;
      if (cmsg->cmsg_level == SOL_SOCKET &&
          cmsg->cmsg_type == SCM_TIMESTAMP &&
          cmsg->cmsg_len == CMSG_LEN(sizeof(time_kernel))) {
        memcpy(&time_kernel, CMSG_DATA(cmsg), sizeof(time_kernel));
        // 将 timeval 转换为纳秒，方便与用户时间戳比较。
        kernel_time = time_kernel.tv_sec * NANOS_TO_SECS + time_kernel.tv_usec * NANOS_TO_MICROS;
      }

      const auto user_time = getCurrentNanos();  // 用户态当前时间戳。

      // 通过 Logger 记录一次收包：包括 socket fd / 长度 / 用户与内核时间差。
      logger_.log("%:% %() % read socket:% len:% utime:% ktime:% diff:%\n", __FILE__, __LINE__, __FUNCTION__,
                  Common::getCurrentTimeStr(&time_str_), socket_fd_, next_rcv_valid_index_, user_time, kernel_time, (user_time - kernel_time));
      // 调用上层回调，交由业务线程处理数据；注意回调在网络线程执行。
      recv_callback_(this, kernel_time);
    }

    if (next_send_valid_index_ > 0) {
      // 非阻塞发送缓冲区数据，使用 MSG_NOSIGNAL 防止对端关闭导致 SIGPIPE。
      const auto n = ::send(socket_fd_, outbound_data_.data(), next_send_valid_index_, MSG_DONTWAIT | MSG_NOSIGNAL);
      logger_.log("%:% %() % send socket:% len:%\n", __FILE__, __LINE__, __FUNCTION__,
                  Common::getCurrentTimeStr(&time_str_), socket_fd_, n);
    }
    next_send_valid_index_ = 0;  // 无论成功与否都重置游标；失败重试由上层控制。

    return (read_size > 0);
  }

  /// Write outgoing data to the send buffers.
  auto TCPSocket::send(const void *data, size_t len) noexcept -> void {
    // 将数据拷贝入发送缓冲区，等待 sendAndRecv() 统一发送。
    memcpy(outbound_data_.data() + next_send_valid_index_, data, len);
    next_send_valid_index_ += len;
  }
}  // namespace Common